// A listener for the bookmarks
var swappSpy_bookmarkListener = {
	onBeginUpdateBatch: function() {},
	onEndUpdateBatch: function() {},
	onItemAdded: function(aItemId, aFolder, aIndex) {
		var thisUrl = swappSpy.bmsvc.getBookmarkURI(aItemId).spec;
		var thisTitle = swappSpy.bmsvc.getItemTitle(aItemId);
		swappSpy.onBookmark(thisUrl);
	},
	onItemRemoved: function(aItemId, aFolder, aIndex) {},
	onItemChanged: function(aBookmarkId, aProperty, aIsAnnotationProperty, aValue) {},
	onItemVisited: function(aBookmarkId, aVisitID, time) {},
	onItemMoved: function(aItemId, aOldParent, aOldIndex, aNewParent, aNewIndex) {}
	//QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsINavBookmarkObserver])
};

// A listener for the location bar
var swappSpy_urlBarListener = {	
	QueryInterface: function(aIID){
		if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
       	    aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
       		aIID.equals(Components.interfaces.nsISupports))
     	return this;
   		throw Components.results.NS_NOINTERFACE;
  	},
  	onLocationChange: function(aProgress, aRequest, aURI){
    	swappSpy.onNewUrl(aURI);
  	},
	onStateChange: function() {},
	onProgressChange: function() {},
	onStatusChange: function() {},
	onSecurityChange: function() {},
	onLinkIconAvailable: function() {}
};

// A class for the datas associated with an url
function urlData(url) {
	this.url = url;				// the url of the document
	this.time = 0;				// the time of consultation in milliseconds
	this.bookmarked = false;	// is the url bookmarked ?
	this.bookmarkedNow = false;	// has the url been bookmarked now ?
	this.printed = false;		// has the document been printed ?
	this.saved = false;			// has the document been saved ?
	this.copiedTexts = new Array(); // texts that have been copied
	
	/*
	 * function disp()
	 * To have a string representation of the data.
	 * @return a pretty string of the data
	 */
	this.disp = function(){
		var res = "[URL] "+this.url
			+"\n[Consultation time] "+this.time
			+"\n[Bookmarked] "+(this.bookmarked?"Yes":"No")
			+"\n[Bookmarked now] "+(this.bookmarkedNow?"Yes":"No")
			+"\n[Printed] "+(this.printed?"Yes":"No")
			+"\n[Saved] "+(this.saved?"Yes":"No");
		res += "\n[Copied texts] " + (this.copiedTexts.length==0?"-None-":"");
		for(var index=0; index<this.copiedTexts.length; index++){
			res += "\n\t'"+this.copiedTexts[index]+"'";
	    }
		return res;
	};
	
	/*
	 * function addTime(t)
	 * To add some consultation time to a document.
	 * @param t: the time to add
	 * @return the total consultation time
	 */
	this.addTime = function(t){
		this.time += t;
		return this.time;
	};
	
	/*
	 * function bmNow()
	 * To set that the document has just been bookmarked.
	 */
	this.bmNow = function(){
		this.bookmarked = true;
		this.bookmarkedNow = true;
	};
	
	/*
	 * function addCopiedText(text)
	 * To add a text to the list of the copied texts within the document.
	 * @param text: the copied text
	 */
	this.addCopiedText = function(text){
		this.copiedTexts.push(text);
	}
	
	this.setReferrer = function(url){
		this.referrer = url;
	}
}

/*
 * The actual extension
 */ 
var swappSpy = {
	
	oldURL: null,			// the previous url
	currentURL: null,		// the current url
	urls: new Array(),		// all the urls that are opened in the browser
	startTime: null,		// the last time of the beginning of a consultation
	activityTimeout: null, 	// the timeout concerning the timeout inactivity
	inActivity: true,		// is the user active now ?
	// the bookmarks service of Mozilla Firefox
	bmsvc: Components.classes["@mozilla.org/browser/nav-bookmarks-service;1"].getService(Components.interfaces.nsINavBookmarksService),
	// the i/o service of Mozilla Firefox
	ios: Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService),
	// the preferences service
	prefs: Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService),
	
	inactivityThresholdTime: 50000,	// after this time (in milliseconds) w/o user activity, consider user not active
	dialogURL: "chrome://swappSpy/content/swappSpyConfig.xul",
	
	xmlRequest: null, 		// XMLHttpRequest object to send the data
	xmlWaitingDelay: 1000,	// waiting time if data needs to be sent but the server is not ready
	// the url that triggered the WBI proxy plugin that received the data
	proxyMEGMonitAddress: "http://ifeedback.swapp.smac.irit.fr",
	browserClosing: false, // to know if the browser is closing
	
	/**
	 * function getDocTime()
	 * To know how much time the user has consulted the current document.
	 * @return the consultation time of the document
	 */
	getDocTime: function() {
  		var d = new Date();
    	var t = d.getTime();
    	var res = (swappSpy.startTime?t-swappSpy.startTime:0);
    	swappSpy.startTime = t;
    	return res;
  	},
  	
  	/**
  	 * function isActive()
  	 * To know whether the extension is active or not.
  	 * @return true if the user has activated the extension, false otherwise.
  	 */
  	isActive: function() {
        var SSprefs = swappSpy.prefs.getBranch("extensions.swappspy.")
		return SSprefs.getBoolPref("active");
  	},
  	
  	/**
  	 * function addTimeToUrl(url,t)
  	 * To add an amount of time to an url in the array of all the urls.
  	 * @param url: the url to wich add consultation time
  	 * @param t: the amount of time to add
  	 */
  	addTimeToUrl: function(url,t) {
  		if(url.substr(0,6) == "about:") return;
  		swappSpy.urls[url].addTime(t);
  	},
  	
  	/**
  	 * function dispUrlData(url)
  	 * To display the informations binded to an url in a pretty way.
  	 * @param url: 
  	 * @return the string representation of the informations
  	 */
  	dispUrlData: function(url) {
  		if(url.substr(0,6) == "about:") return;
  		return swappSpy.urls[url].disp();
  	},
  	
  	/**
  	 * function compareUrls(u1,u2)
  	 * To know if the 2 urls refer to the same document.
  	 * Warning: the # form
  	 * @param u1: the first url
  	 * @param u2: the second url
  	 */
  	compareUrls: function(u1,u2) {
  		if(u1 == u2) return true;
  		if(u1.lastIndexOf("#") == u2.length 
  			&& u1.substr(0,u2.length) == u2) return true;
  		if(u2.lastIndexOf("#") == u1.length 
  			&& u2.substr(0,u1.length) == u1) return true;
  		return false;
  	},
  	
  	/**
  	 * function heckAddUrl(url)
  	 * Check in the array of urls if the url already exist, if not, add it in this array.
  	 * @param url: the url to add if necessary in the array
  	 */
  	checkAddUrl: function(url) {
  		if(url.substr(0,6) == "about:" || url.substr(0,7) == "chrome:") return;
  		var found = false;
  		for(var url2 in swappSpy.urls){
			if(swappSpy.compareUrls(url2,url)){
				found = true;
				break;
			}
	    }
  		if(!found){
    		// if this url was not active, we had it to the array
  			swappSpy.logMessage("new: "+url);
    		swappSpy.urls[url] = new urlData(url);
    	}
  	},
  	
  	/**
  	 * function sendAndRemoveData(url)
  	 * When a document is no longer consulted, send datas, then remove it.
  	 * Before sending data, the function check if the url is bookmarked.
  	 * This function also check is the document is not consulted in another tab.
  	 * Note: if the function has been called after removing a tab, the "removed" tab is still active
  	 * that's why 1 tab is allowed to contain the same url. If this function is called after loading
  	 * a new document, no other tab are allowed to contain it.
  	 * @param url: the url of the concerned document
  	 * @param nbOfOtherTab: the number of other tabs that are allowed to have the same url.
  	 */
  	sendAndRemoveData: function(url,nbOfOtherTab) {
  		if(url == null || url.substr(0,6) == "about:") return;
	  	var foundTab = 0;
	    // Check each tab for the url
	    var numTabs = gBrowser.browsers.length;
	    for(var index=0; index<numTabs; index++) {
	      var currentBrowser = gBrowser.getBrowserAtIndex(index);
	      if(swappSpy.compareUrls(url,currentBrowser.currentURI.spec)) {
	        // another tab contains the same url
	        foundTab ++;
	      }
	    }
	    //alert(foundTab);
		if(foundTab<=nbOfOtherTab){ // the document is NOT consulted in another tab
			// Check if the url is bookmaked
			var uri = swappSpy.ios.newURI(url, null, null);
			swappSpy.urls[url].bookmarked = swappSpy.bmsvc.isBookmarked(uri);
	  		// Send data
			swappSpy.sendXMLHttpRequest(swappSpy.urls[url]);
		}else{ // the document is consulted in another tab
			// Do nothing
			swappSpy.logMessage("Send nothing because document consulted in another tab...");
		}
  	},
  	
  	/**
  	 * function sendXMLHttpRequest(urlObject)
  	 * This function is used to send the collected data to the SWAPP proxy.
  	 * It uses the XMLHttpRequest object to send the data in an asynchronous way.
  	 * @param urlObject: 
  	 */
  	sendXMLHttpRequest: function(urlObject) {
  		if(urlObject.url == null) return;
  		if(window.XMLHttpRequest) {
  			//alert("trying to send: "+urlObject.url);
	  		if(swappSpy.xmlRequest != null){
	  			// the last request have not been finished yet
	  			// try again later
	  			swappSpy.logMessage("waiting for: "+urlObject.url);
	  			var sendFunction = function() { swappSpy.sendXMLHttpRequest(urlObject); };
	  			setTimeout(sendFunction, swappSpy.xmlWaitingDelay);
	  		} else {
	  			swappSpy.xmlRequest = new XMLHttpRequest();
	  			var asynchronousFlag = swappSpy.browserClosing?false:true;
	  			//if(!asynchronousFlag) alert("mode synchrone");
	  			swappSpy.xmlRequest.open("POST", swappSpy.proxyMEGMonitAddress, asynchronousFlag);
	  			swappSpy.xmlRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	  			
	  			// pack the copied texts
	  			var separator = "\u00FF";
	  			var copiedText = urlObject.copiedTexts;
	  			var textString = "";
	  			if(copiedText){
		  			for(var i=0; i < copiedText.length; i++) {
		  				textString += copiedText[i] + separator;
		  			}		
	  			}
	  			
	  			// pack all the data
	  			var encoded = "";
				encoded = "url=" + escape(urlObject.url) +
				"&inspectingTime=" + escape(urlObject.time) +
				"&isBookmarked=" + escape(urlObject.bookmarked) +
				"&hasBeenBookmarked=" + escape(urlObject.bookmarkedNow) +
				"&hasBeenSaved=" + escape(urlObject.saved) +
				"&hasBeenPrinted=" + escape(urlObject.printed) +
				"&copiedText=" + escape(textString);

				// when the server will send a response, the onXMLResponse
				// function will be called
				if(asynchronousFlag) swappSpy.xmlRequest.onreadystatechange = swappSpy.onXMLResponse;
				swappSpy.logMessage("sending data about:\n"+urlObject.url);//+"\n"+encoded+"\nasynchrone? "+asynchronousFlag);
				swappSpy.xmlRequest.send(encoded);
				
				// the user is closing the browser so we need to be in synchronous mode
				if(!asynchronousFlag){
					swappSpy.logMessage("Data about:\n"
						+swappSpy.xmlRequest.getResponseHeader("url")
						+"\nsent in synchronous mode!");
					// Delete data
					delete swappSpy.urls[swappSpy.xmlRequest.getResponseHeader("url")];
					// a new request can be sent to the server
					swappSpy.xmlRequest = null;
				}
	  		}
  		}
  	},
  	
  	/**
  	 * function onXMLResponse()
  	 * Called when the server send a response to the extension.
  	 * It just delete the sent data and the XMLHttpRequest object to
  	 * allow another request to be send.
  	 */
  	onXMLResponse: function() {
  		if (swappSpy.xmlRequest.readyState != 4) {
  			// The response is not ready
		    return;
		}
		//swappSpy.logMessage(swappSpy.xmlRequest.status);
		if (swappSpy.xmlRequest.status == 200) {
			//if (swappSpy.xmlRequest.responseXML) {
		    	// The response is ready and the status ok
				swappSpy.logMessage("Data about:\n"
						+swappSpy.xmlRequest.getResponseHeader("url")
						+"\nsent in asynchronous mode!");
				// Delete data
				delete swappSpy.urls[swappSpy.xmlRequest.getResponseHeader("url")];
		    //}
		} else {
			// The web server gave us an error
			swappSpy.logMessage("Web server gave us an error.")
		}
		// a new request can be sent to the server
		swappSpy.xmlRequest = null;
  	},
  	
  	/**
  	 * function backupPrefs()
  	 * Memorize all the user settings concerning the proxy before configuring
  	 * Firefox according to the extension settings.
  	 * This function also set the extension preference 'active' true.
  	 */
  	backupPrefs: function() {
  		// Backup all the user settings concerning the proxy
		var prefs = swappSpy.prefs.getBranch("extensions.swappspy.");
		var prefs2 = swappSpy.prefs.getBranch("network.proxy.");
		var prefs3 = swappSpy.prefs.getDefaultBranch("network.proxy.");
		
		prefs.setIntPref("user.autoconfig_retry_interval_max",prefs2.getIntPref("autoconfig_retry_interval_max"));
		prefs.setIntPref("user.autoconfig_retry_interval_min",prefs2.getIntPref("autoconfig_retry_interval_min"));
		prefs.setIntPref("user.failover_timeout",prefs2.getIntPref("failover_timeout"));
		prefs.setIntPref("user.ftp_port",prefs2.getIntPref("ftp_port"));
		prefs.setIntPref("user.gopher_port",prefs2.getIntPref("gopher_port"));
		prefs.setIntPref("user.http_port",prefs2.getIntPref("http_port"));
		prefs.setIntPref("user.socks_port",prefs2.getIntPref("socks_port"));
		prefs.setIntPref("user.socks_version",prefs2.getIntPref("socks_version"));
		prefs.setIntPref("user.ssl_port",prefs2.getIntPref("ssl_port"));
		prefs.setIntPref("user.type",prefs2.getIntPref("type"));
		prefs.setCharPref("user.autoconfig_url",prefs2.getCharPref("autoconfig_url"));
		prefs.setCharPref("user.ftp",prefs2.getCharPref("ftp"));
		prefs.setCharPref("user.gopher",prefs2.getCharPref("gopher"));
		prefs.setCharPref("user.http",prefs2.getCharPref("http"));
		prefs.setCharPref("user.socks",prefs2.getCharPref("socks"));
		prefs.setCharPref("user.ssl",prefs2.getCharPref("ssl"));
		prefs.setCharPref("user.no_proxies_on",prefs2.getCharPref("no_proxies_on"));
		prefs.setBoolPref("user.share_proxy_settings",prefs2.getBoolPref("share_proxy_settings"));
		prefs.setBoolPref("user.socks_remote_dns",prefs2.getBoolPref("socks_remote_dns"));
		
		// set the extension active
		prefs.setBoolPref("active", true);		
		
		// Set all the settings to their default values...
		prefs2.setIntPref("autoconfig_retry_interval_max",prefs3.getIntPref("autoconfig_retry_interval_max"));
		prefs2.setIntPref("autoconfig_retry_interval_min",prefs3.getIntPref("autoconfig_retry_interval_min"));
		prefs2.setIntPref("failover_timeout",prefs3.getIntPref("failover_timeout"));
		prefs2.setIntPref("ftp_port",prefs3.getIntPref("ftp_port"));
		prefs2.setIntPref("gopher_port",prefs3.getIntPref("gopher_port"));
		prefs2.setIntPref("socks_port",prefs3.getIntPref("socks_port"));
		prefs2.setIntPref("socks_version",prefs3.getIntPref("socks_version"));
		prefs2.setIntPref("ssl_port",prefs3.getIntPref("ssl_port"));
		prefs2.setCharPref("autoconfig_url",prefs3.getCharPref("autoconfig_url"));
		prefs2.setCharPref("ftp",prefs3.getCharPref("ftp"));
		prefs2.setCharPref("gopher",prefs3.getCharPref("gopher"));
		prefs2.setCharPref("socks",prefs3.getCharPref("socks"));
		prefs2.setCharPref("ssl",prefs3.getCharPref("ssl"));
		prefs2.setCharPref("no_proxies_on",prefs3.getCharPref("no_proxies_on"));
		prefs2.setBoolPref("share_proxy_settings",prefs3.getBoolPref("share_proxy_settings"));
		prefs2.setBoolPref("socks_remote_dns",prefs3.getBoolPref("socks_remote_dns"));
		
		// ...except the ones concerning the http proxy
		prefs2.setCharPref("http",prefs.getCharPref("http"));
		prefs2.setIntPref("http_port",prefs.getIntPref("http_port"));
		prefs2.setIntPref("type",1);	
  	},
  	
  	/**
  	 * function switchState(event)
  	 * Function called when the user click on the extension image in the
  	 * status bar. It toggle the extension state.
  	 * @param event: the event that triggered this function
  	 */
  	switchState: function(event) {	
		if(event.button == 0) {   //if left click
			if(swappSpy.isActive()){
				swappSpy.deactivate();
			}else{
				swappSpy.activate();
			}
		}
	},
	
	/**
	 * function setStatusImage(state)
	 * Change the extension image in the status bar according to the state parameter.
	 * If state is true, the function set the image state to on ; if state is false,
	 * it set the image state to off.
	 * @param state: to set the state of the extension image to on if true, off if false.
	 */
	setStatusImage: function(state) {
		var swappSpystatusImage = window.document.getElementById("swappspy-status-image");
		swappSpystatusImage.setAttribute("status", (state?"on":"off"));
	},
  	
	/**
	 * function setListeners()
	 * To set all the listeners when initializing or activating the extension.
	 */
  	setListeners: function() {
  		// Listen for location change
    	gBrowser.addProgressListener(swappSpy_urlBarListener,
       		Components.interfaces.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
       		
       	// Listen for tab close or select
       	var container = gBrowser.tabContainer;
		container.addEventListener("TabClose", this.onTabRemoved, false);
		
		// Listen for page load
		document.getElementById("appcontent").addEventListener("DOMContentLoaded", this.onPageLoad, true);
		
		// Listen to changes concerning bookmarks
		swappSpy.bmsvc.addObserver(swappSpy_bookmarkListener, false);
		
		//listener for the corresponding shortcut key press event and the menu item click event
		window.addEventListener("keydown", this.onKeyPressed, false);
		window.addEventListener("command", this.onMenuItemSelected, false);
		
		// listeners for the user activity
		window.addEventListener("keydown", this.onActivityDetected, false);
		window.addEventListener("click", this.onActivityDetected, false);
		window.addEventListener("DOMMouseScroll", this.onActivityDetected, false);
  	},
  	
  	/**
  	 * function removeListeners()
  	 * To remove all the listeners when uninitializing or desactivating the extension.
  	 */
  	removeListeners: function() {
		gBrowser.removeProgressListener(swappSpy_urlBarListener);
		var container = gBrowser.tabContainer;
		container.removeEventListener("TabClose", this.onTabRemoved, false);
		document.getElementById("appcontent").removeEventListener("DOMContentLoaded", this.onPageLoad, true);
		swappSpy.bmsvc.removeObserver(swappSpy_bookmarkListener);
		window.removeEventListener("keydown", this.onKeyPressed, false);
		window.removeEventListener("command", this.onMenuItemSelected, false);
		window.removeEventListener("keydown", this.onActivityDetected, false);
		window.removeEventListener("click", this.onActivityDetected, false);
		window.removeEventListener("DOMMouseScroll", this.onActivityDetected, false);
  	},
	
  	/**
  	 * function init()
  	 * Called when initializing the extension.
  	 * It checks if the extension is active and if so, it adds all the
  	 * listeners, saves all the user preferences concerning the proxy settings,
  	 * and set the timeout for the inactivity.
  	 */
	init: function() {
		if(swappSpy.isActive()){ // The extension is ACTIVE
			// add all listeners
			swappSpy.setListeners();
			// memorize all the user preferences concerning the proxy settings
			swappSpy.backupPrefs();
			// set the timeout for the detection of user inactivity
			swappSpy.activityTimeout = setTimeout(swappSpy.onInactivity,swappSpy.inactivityThresholdTime);
			// set the startTime for document consultation
			swappSpy.startTime = new Date().getTime();
		}else{ // The extension is NOT active
			swappSpy.setStatusImage(false);
		}
		swappSpy.logMessage("Extension intialized");
  	},
  	
  	/**
  	 * function activate()
  	 * Called when activating the extension.
  	 * It adds all the listeners, sets the inactivity timeout,
  	 * saves all the user preferences concerning the proxy settings,
  	 * set the state of the extension image in the status bar to 'on'.
  	 * Finally, it create datas for all the opened documents.  	 * 
  	 */
  	activate: function() {
  		// add all listeners
  		swappSpy.setListeners();
		
		// set the timeout for the detection of user inactivity
		swappSpy.activityTimeout = setTimeout(swappSpy.onInactivity,swappSpy.inactivityThresholdTime);
  		
  		// memorize all the user preferences concerning the proxy settings
  		swappSpy.backupPrefs();		
		
		swappSpy.setStatusImage(true);
  		
  		// Create data for all opened tabs
	    var numTabs = gBrowser.browsers.length;
	    for(var index=0; index<numTabs; index++) {
	      var currentBrowser = gBrowser.getBrowserAtIndex(index);
	      swappSpy.checkAddUrl(currentBrowser.currentURI.spec);
	    }
	    
	    // set the currentURL
	    swappSpy.currentURL = gBrowser.selectedBrowser.currentURI.spec;
	    
	    // reset the startTime for document consultation
		swappSpy.startTime = new Date().getTime();
	    
	    swappSpy.logMessage("Extension activated");
  	},  	
  	
  	/**
  	 * function uninit()
  	 * Called during the unitialization of the extension.
  	 * The function checks if the extension is active, and if so,
  	 * removes all the listeners, clears the inactivity timeout,
  	 * and then updtae and send all remaining datas.
  	 */
	uninit: function() {
		if(swappSpy.isActive()){ // the extension is ACTIVE
			swappSpy.browserClosing = true;
			// remove all listeners
			swappSpy.removeListeners();	
			// clear the inactivity timeout
			clearTimeout(swappSpy.activityTimeout);
			
			// update consultation time for the current url
			if(swappSpy.currentURL && swappSpy.currentURL.substr(0,6) != "about:"){
				var docTime = swappSpy.getDocTime();
				swappSpy.urls[swappSpy.currentURL].addTime(docTime);
			}
			// send all remaining datas
			for(var url in swappSpy.urls){
				swappSpy.sendAndRemoveData(url,1);
		    }
		}
		swappSpy.logMessage("Extension unintialized");
	},
	
	/**
	 * function deactivate()
	 * Called when desactivating the extension.
	 * This function removes all listeners, clear the inactivity timeout,
	 * update and send all the remaining datas and finally, restores all
	 * the user preferences concerning the proxy settings.
	 * It also set the extension inactive.
	 */
	deactivate: function() {
		// remove all listeners
		swappSpy.removeListeners();	
		// clear the inactivity timeout
		clearTimeout(swappSpy.activityTimeout);
		
		// update consultation time for the current url
		if(swappSpy.currentURL && swappSpy.currentURL.substr(0,6) != "about:"){
			var docTime = swappSpy.getDocTime();
			swappSpy.urls[swappSpy.currentURL].addTime(docTime);
		}
		// send all datas
		for(var url in swappSpy.urls){
			//alert(url);
			swappSpy.sendAndRemoveData(url,1);
	    }		
		
	    var prefs = swappSpy.prefs.getBranch("network.proxy.");	
		var prefs2 = swappSpy.prefs.getBranch("extensions.swappspy.user.");
		var prefs3 = swappSpy.prefs.getBranch("extensions.swappspy.");
		
		// restore all the user preferences concerning the proxy settings
		prefs.setIntPref("autoconfig_retry_interval_max",prefs2.getIntPref("autoconfig_retry_interval_max"));
		prefs.setIntPref("autoconfig_retry_interval_min",prefs2.getIntPref("autoconfig_retry_interval_min"));
		prefs.setIntPref("failover_timeout",prefs2.getIntPref("failover_timeout"));
		prefs.setIntPref("ftp_port",prefs2.getIntPref("ftp_port"));
		prefs.setIntPref("gopher_port",prefs2.getIntPref("gopher_port"));
		prefs.setIntPref("http_port",prefs2.getIntPref("http_port"));
		prefs.setIntPref("socks_port",prefs2.getIntPref("socks_port"));
		prefs.setIntPref("socks_version",prefs2.getIntPref("socks_version"));
		prefs.setIntPref("ssl_port",prefs2.getIntPref("ssl_port"));
		prefs.setIntPref("type",prefs2.getIntPref("type"));
		prefs.setCharPref("autoconfig_url",prefs2.getCharPref("autoconfig_url"));
		prefs.setCharPref("ftp",prefs2.getCharPref("ftp"));
		prefs.setCharPref("gopher",prefs2.getCharPref("gopher"));
		prefs.setCharPref("http",prefs2.getCharPref("http"));
		prefs.setCharPref("socks",prefs2.getCharPref("socks"));
		prefs.setCharPref("ssl",prefs2.getCharPref("ssl"));
		prefs.setCharPref("no_proxies_on",prefs2.getCharPref("no_proxies_on"));
		prefs.setBoolPref("share_proxy_settings",prefs2.getBoolPref("share_proxy_settings"));
		prefs.setBoolPref("socks_remote_dns",prefs2.getBoolPref("socks_remote_dns"));
		
		// set the extension inactive
		prefs3.setBoolPref("active", false);

		swappSpy.setStatusImage(false);
		
		swappSpy.logMessage("Extension deactivated");
	},
	
	/**
	 * function onKeyPressed(event)
	 * Function called when the user press a key of his keyboard.
	 * @param event: the event that triggered this function
	 */
	onKeyPressed : function(event) {
		if(event.ctrlKey && (event.keyCode == 67)) {   //ctrl + c pressed
			swappSpy.onCopy();
		} else if(event.ctrlKey && (event.keyCode == 80)) {   //ctrl + p pressed
			swappSpy.onPrint();
		} else if(event.ctrlKey && (event.keyCode == 83)) {   //ctrl + s pressed
			swappSpy.onSave();
		}
	},

	/**
	 * function onMenuItemSelected(event)
	 * Function called when the user use a command of the browser.
	 * @param event: the event that triggered this function
	 */
	onMenuItemSelected : function(event) {
		if(event.target.id == "cmd_copy") {   //menuitem 'Copy' clicked
			swappSpy.onCopy();
		} else if(event.target.id == "cmd_print") {   //menuitem 'Print' clicked
			swappSpy.onPrint();
		} else if(event.target.id == "Browser:SavePage") {   //menuitem 'Sace page as' clicked
			swappSpy.onSave();
		}
	},

	/**
	 * function onNewUrl(aURI)
	 * Function called whenever the url in the location bar changes.
	 * @param aURI: the new URI
	 */
  	onNewUrl: function(aURI) {
  		if(aURI == null // a new tab is opened w/o url
  			|| !swappSpy.currentURL // first document open
  			|| !swappSpy.compareUrls(aURI.spec,swappSpy.currentURL)){ // new document
	    	var docTime = swappSpy.getDocTime();
	    	if(docTime != -1 
	    		&& swappSpy.urls[swappSpy.currentURL]){ // if currentURL's tab removed
	    		// if the user is not active, the time has already been added
	    		if(swappSpy.inActivity)	swappSpy.addTimeToUrl(swappSpy.currentURL,docTime);
	    	}
	    	swappSpy.oldURL = swappSpy.currentURL;
	    	// if a new tab is opened w/o url, aURI is null but the doc is no longer consulted
	    	swappSpy.currentURL = (aURI?aURI.spec:"about:blank");
	    	
	    	swappSpy.checkAddUrl(swappSpy.currentURL);
  		}
  	},

  	/**
  	 * function onTabRemoved(event)
  	 * Function called whenever a tab is removed.
  	 * @param event: the event that triggered the function
  	 */
  	onTabRemoved: function(event) {
		var urlRemoved = event.target.linkedBrowser.currentURI.spec;
		var browser = gBrowser.getBrowserAtIndex(gBrowser.mTabContainer.selectedIndex);
		if(urlRemoved == browser.currentURI.spec){
			// The current tab is removed
			var docTime = swappSpy.getDocTime();
			// if the user is not active, the time has already been added
	    	if(swappSpy.inActivity)	swappSpy.addTimeToUrl(urlRemoved,docTime);
		}
		swappSpy.sendAndRemoveData(urlRemoved,1);
  	},

  	/**
  	 * function onPageLoad(event)
  	 * Function called whenever a page is loaded.
  	 * @param event: the event that triggered the function
  	 */
  	onPageLoad: function(event) {
  		if(event.originalTarget.nodeName == "#document"){
    		var doc = event.originalTarget; // document that triggered "onload" event
    		var browser = gBrowser.getBrowserAtIndex(gBrowser.mTabContainer.selectedIndex);
    		if(swappSpy.currentURL == doc.location.href 
    			&& browser.currentURI.spec != "about:blank"){ // document loaded in the active tab
    			swappSpy.sendAndRemoveData(swappSpy.oldURL,0);
    		}else{
    			// document loaded in a background tab
    			swappSpy.checkAddUrl(doc.location.href);
    		}
  		}    	
  	},
  	
  	/**
  	 * function onBookmark(url,title)
  	 * To add or change the title of a bookmarked url.
  	 * @param url: the bookmarked url
  	 */
  	onBookmark: function(url) {
  		if(url.substr(0,6) == "about:") return;
  		// for dynamic bookmarks that are not vivited, don't want them in the datas
  		if(swappSpy.urls[url]){
  			swappSpy.urls[url].bmNow();
  			swappSpy.logMessage("Document bookmarked: \n["
  								+ url + "].");
  		}  		
  	},
  	
  	/**
  	 * function onCopy()
  	 * Function called when the user is copying some part of a web page.
  	 */
  	onCopy : function() {
		var copiedText = gBrowser.contentWindow.getSelection().toString();
		var url = gBrowser.contentWindow.location.href;	
		
		var logstr = "Text copied: \n[" + copiedText + "]. \nFrom address: \n[" + url + "].";		
		swappSpy.logMessage(logstr);
		
		swappSpy.urls[url].addCopiedText(copiedText);
	},

  	/**
  	 * function onPrint()
  	 * Function called when the user is printing a web page.
  	 */
	onPrint : function() {
		//var pageTitle = gBrowser.contentWindow.title;
		var pageTitle = gBrowser.contentWindow.document.title;
		var url = gBrowser.contentWindow.location.href;
		
		var logstr = "Page printed: \n[" + pageTitle + "]. \nFrom address: \n[" + url + "].";		
		swappSpy.logMessage(logstr);
		
		swappSpy.urls[url].printed = true;
	},
	
  	/**
  	 * function onSave()
  	 * Function called when the user is saving a web page.
  	 */
	onSave : function() {
		//var pageTitle = gBrowser.contentWindow.title;
		var pageTitle = gBrowser.contentWindow.document.title;
		var url = gBrowser.contentWindow.location.href;
		
		var logstr = "Page saved: \n[" + pageTitle + "]. \nFrom address: \n[" + url + "].";		
		swappSpy.logMessage(logstr);
		
		swappSpy.urls[url].saved = true;
	},
	
	/**
	 * function onActivityDetected(event)
	 * Function called when the user press a key, click or scroll.
	 * @param event: the event that triggered the function
	 */
	onActivityDetected: function(event){
		if(!swappSpy.inActivity){
			// user was inactive
			swappSpy.startTime = new Date().getTime();
			swappSpy.logMessage("User activity resumed.");
		}
		swappSpy.inActivity = true;
		clearTimeout(swappSpy.activityTimeout);
		swappSpy.activityTimeout = setTimeout(swappSpy.onInactivity,swappSpy.inactivityThresholdTime);
	},
	
	/**
	 * function onInactivity()
	 * Function called when the user has not been active during
	 * 'inactivityThresholdTime' milliseconds.
	 */
	onInactivity: function(){
		if(!swappSpy.currentURL || swappSpy.currentURL.substr(0,6) == "about:") return;
		swappSpy.inActivity = false;
		swappSpy.logMessage("Inactivity detected.");
		swappSpy.urls[swappSpy.currentURL].addTime(swappSpy.getDocTime());
	},
	
	/**
	 * function logMessage()
	 * To get the console service in order to print some messages in the console.
	 * @return the console service of Firefox
	 */
	logMessage : function(message) {
		var aConsoleService = Components.classes["@mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService);
		aConsoleService.logStringMessage(message);
	},
	
	/**
	 * function openConfigDialog()
	 * Called when the user want to configure the extension.
	 * It opens a dialog window to let the user set the proxy settings.
	 */
	openConfigDialog: function() {
		var windows = Components.classes['@mozilla.org/appshell/window-mediator;1']
						.getService(Components.interfaces.nsIWindowMediator).getEnumerator(null);
	
		while(windows.hasMoreElements()) {
			var win = windows.getNext();
			if(win.document.documentURI == swappSpy.dialogURL) {
				win.focus();
				return;
			}
		}
		var features = "chrome,titlebar,toolbar,centerscreen,modal";
		openDialog(swappSpy.dialogURL, "Preferences", features);
	}
};

// Initializing the extension when Firefox is loaded
window.addEventListener("load", function() {swappSpy.init()}, false);
// Uninitialiseing the extension when Firefox is closed
window.addEventListener("unload", function() {swappSpy.uninit()}, false);